package com.wave.system.thread;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.serotonin.modbus4j.code.DataType;
import com.wave.common.utils.StringUtils;
import com.wave.common.utils.redis.RedisUtils;
import com.wave.common.utils.spring.SpringUtils;
import com.wave.system.domain.SysProductQuery;
import com.wave.system.domain.SysToolBoardLine;
import com.wave.system.domain.SysToolBoardTask;
import com.wave.system.mapper.SysProductQueryMapper;
import com.wave.system.mapper.SysToolBoardLineMapper;
import com.wave.system.mapper.SysToolBoardTaskMapper;
import com.wave.system.runner.SystemApplicationRunner;
import com.wave.system.service.ISysNgRecordService;
import com.wave.system.service.ISysProduceArrangeService;
import com.wave.system.util.Modbus4jUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.Socket;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class A1RobotScanCodeListenerThread implements Runnable {

    private ISysProduceArrangeService sysProduceArrangeService = SpringUtils.getBean(ISysProduceArrangeService.class);
    private ISysNgRecordService sysNgRecordService = SpringUtils.getBean(ISysNgRecordService.class);
    private SysToolBoardTaskMapper sysToolBoardTaskMapper = SpringUtils.getBean(SysToolBoardTaskMapper.class);
    private SysToolBoardLineMapper sysToolBoardLineMapper = SpringUtils.getBean(SysToolBoardLineMapper.class);
    private SysProductQueryMapper sysProductQueryMapper = SpringUtils.getBean(SysProductQueryMapper.class);

    @Override
    public void run() {
        while (true) {
            try {
                boolean allowScanCode = Modbus4jUtils.readCoilStatus(1, 4824);
                if (allowScanCode) {
                    log.info("收到PLC通知上位机A1机器人拍照指令");
                    Socket socket = SystemApplicationRunner.socketMap.get("visualSocket");
                    if (null == socket) {
                        log.info("视觉客户端还未连接,等待视觉客户端上线");
                        TimeUnit.SECONDS.sleep(1L);
                        continue;
                    }
                    String pickupLocation = SystemApplicationRunner.armList.get(0).getPickupLocation();
                    if (StringUtils.isBlank(pickupLocation)) {
                        log.warn("A1机器人拍照无法获取取货位置");
                        TimeUnit.MILLISECONDS.sleep(100L);
                        continue;
                    }
                    String snCode = SystemApplicationRunner.getVisualCodeByRetry(socket, 1);

                    //查看是否有手动设置的
                    if (RedisUtils.getCacheObject("a1ccdsncodecache")!=null) {
                        snCode = RedisUtils.getCacheObject("a1ccdsncodecache");
                        log.info("a1机器人：获取到手动设置的ccd拍照sn码：{}", snCode);
                        //删除手动设置的sn码
                        RedisUtils.deleteObject("a1ccdsncodecache");
                    }

                    //ccd相机有时候会返回乱码EOFCamera2Result
                    if (StringUtils.isNotEmpty(snCode) && (snCode.contains("EOF") || snCode.contains("Camera") || snCode.contains("Result"))) {
                        snCode = "";
                    }

                    if (StringUtils.isEmpty(snCode)) {
                        LambdaQueryWrapper<SysToolBoardLine> queryWrapper = Wrappers.lambdaQuery(SysToolBoardLine.class)
                            .eq(SysToolBoardLine::getLineNode, pickupLocation);
                        SysToolBoardLine sysToolBoardLine = sysToolBoardLineMapper.selectOne(queryWrapper);
                        LambdaUpdateWrapper<SysToolBoardTask> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(SysToolBoardTask::getTaskStatus, "CCD拍照失败");
                        updateWrapper.eq(SysToolBoardTask::getProductSn, sysToolBoardLine.getProductSn());
                        sysToolBoardTaskMapper.update(updateWrapper);
                        sysNgRecordService.saveNgAndAlarmRecord(sysToolBoardLine.getProductSn(), "A1机器人CCD拍照失败");
                        boolean b = Modbus4jUtils.writeCoil(1, 4057, true);
                        log.info("发送指令通知A1机器人物料码：{},CCD拍照失败,通知结果：{}", sysToolBoardLine.getProductSn(), b);
                        TimeUnit.MILLISECONDS.sleep(100);
                        continue;
                    }
                    log.info("A1机器人CCD拍照读取到的SN码:{}", snCode);
                    LambdaQueryWrapper<SysToolBoardTask> wrapper = Wrappers.lambdaQuery(SysToolBoardTask.class)
                        .eq(SysToolBoardTask::getProductSn, snCode).last("limit 1");
                    SysToolBoardTask sysToolBoardTask = sysToolBoardTaskMapper.selectOne(wrapper);
                    if (ObjectUtil.isEmpty(sysToolBoardTask)) {
                        log.error("A1机器人拍照读取的SN码:{}找不到对应的工装板任务，临时创建", snCode);
                        /*TimeUnit.MILLISECONDS.sleep(100);
                        continue;*/
                        SysToolBoardTask toolBoardTask = new SysToolBoardTask();
                        toolBoardTask.setProductSn(snCode);
                        toolBoardTask.setPathPoint1("0");
                        toolBoardTask.setPathPoint2("0");
                        toolBoardTask.setPathPoint3("0");
                        toolBoardTask.setTaskStatus("临时创建");
                        sysToolBoardTaskMapper.insert(toolBoardTask);
                    }
                    //计算线号
                    Integer lineNumber = sysProduceArrangeService.confirmLineNumberBySnCode(snCode, true);
                    if (ObjectUtil.isNull(lineNumber)) {
                        log.error("A1机器人sn码:{}计算线号失败", snCode);
                        TimeUnit.MILLISECONDS.sleep(100);
                        continue;
                    }
                    String currentSnCodeKey = "A" + lineNumber + "_CURRENT_SN_CODE";
                    /*String lastSnCode = RedisUtils.getCacheObject(currentSnCodeKey);
                    if (!StringUtils.isEmpty(lastSnCode) && !lastSnCode.equals(snCode)) {
                        log.warn("A1机器人上一个物料码:{}分配到{}号包装线还未处理完，跳过本次监听", lastSnCode, lineNumber);
                        TimeUnit.MILLISECONDS.sleep(50);
                        continue;
                    }*/
                    // 查看该包装线是否有工装架，没有则不处理,休眠
                    String redisKey = "A" + lineNumber + "_SHELF";
                    String shelfNumber = RedisUtils.getCacheObject(redisKey);
                    if (StringUtils.isEmpty(shelfNumber)) {
                        log.warn("物料码:{}计算线号为:{}号包装线,空工装架未到", snCode, lineNumber);
                        SystemApplicationRunner.armList.get(0).setWcsTaskState("入空架中");
                        TimeUnit.SECONDS.sleep(2);
                        continue;
                    }
                    //计算卡槽号
                    Integer slotNumber = sysProduceArrangeService.confirmSlotNumberByShelfNumber(shelfNumber);
                    if (ObjectUtil.isNull(slotNumber)) {
                        log.error("A1机器人sn码:{}获取放料卡槽号未知异常", snCode);
                        sysNgRecordService.saveNgAndAlarmRecord(snCode, "A1机器人获取放料卡槽号失败");
                        TimeUnit.MILLISECONDS.sleep(100);
                        continue;
                    }

                    //更新产品查询的线号-卡槽号字段
                    SysProductQuery sysProductQuery = sysProductQueryMapper.selectOne(Wrappers.lambdaQuery(SysProductQuery.class)
                        .eq(SysProductQuery::getProductSn, snCode));
                    if (ObjectUtil.isEmpty(sysProductQuery)) {
                        SysProductQuery query = new SysProductQuery();
                        query.setProductSn(snCode);
                        query.setLineSolt(lineNumber + "-" + slotNumber);
                        sysProductQueryMapper.insert(query);
                    }
                    if (ObjectUtil.isNotEmpty(sysProductQuery)) {
                        sysProductQuery.setLineSolt(lineNumber + "-" + slotNumber);
                        sysProductQueryMapper.updateById(sysProductQuery);
                    }

                    // 如果相邻包装线都处理过同一物料，把相邻的包装线物料码删除掉(机器人未开机的情况下存在该问题)
                    sysProduceArrangeService.checkRepeatCurrentSnCode(lineNumber, snCode);
                    SystemApplicationRunner.armList.get(0).setWcsTaskState("CCD拍照中");
                    Modbus4jUtils.writeCoil(1, 4056, true);
                    log.info("A1机器人处理物料:{},通知PLC拍照成功", snCode);
                    SystemApplicationRunner.armList.get(0).setScanSnCode(snCode);
                    TimeUnit.MILLISECONDS.sleep(50);
                    Modbus4jUtils.writeHoldingRegister(1, 61, lineNumber, DataType.TWO_BYTE_INT_SIGNED);
                    TimeUnit.MILLISECONDS.sleep(50);
                    Modbus4jUtils.writeHoldingRegister(1, 62, slotNumber, DataType.TWO_BYTE_INT_SIGNED);
                    log.info("A1机器人处理物料：{},放置到{}-{}", snCode, lineNumber, slotNumber);
                    TimeUnit.MILLISECONDS.sleep(50);
                    Modbus4jUtils.writeCoil(1, 4216, true);
                    log.info("A1机器人物料码：{},处理完成", snCode);
                    RedisUtils.setCacheObject(currentSnCodeKey, snCode);
                    SystemApplicationRunner.armList.get(0).setWcsTaskState("抓取中");
                    TimeUnit.MILLISECONDS.sleep(50);
                } else {
                    TimeUnit.MILLISECONDS.sleep(200);
                }
            } catch (Exception e) {
                log.error("A1机械人允许扫码监听异常", e);
            }
        }
    }
}
